package cn.dansj.common.utils.exception;

import cn.dansj.common.utils.transfer.StringUtils;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

public abstract class NestedExceptionUtils {
    private static final int MAX_LENGTH = 2000;
    private static final int HEAD_LINES = 15;  // 保留开头行数
    private static final int TAIL_LINES = 5;   // 保留结尾行数
    private static final int KEY_CONTEXT_LINES = 3; // 关键信息上下文行数
    private static final int MAX_CAUSES = 3;   // 最大异常链深度

    private static final Pattern IMPORTANT_PATTERNS = Pattern.compile(
            "OutOfMemory|Timeout|SQLException|Connection refused|SocketException|NullPointer",
            Pattern.CASE_INSENSITIVE
    );

    /**
     * 获取异常的最底层异常类
     */
    public static Throwable getRootCause(final Throwable exception) {
        Throwable ex = exception;
        while (ex != null) {
            if (ex.getCause() == null) {
                break;
            }
            ex = ex.getCause();
        }
        return ex;
    }

    /**
     * 获取异常的最底层异常类
     */
    @SuppressWarnings("unchecked")
    public static <T extends Throwable> T getRootCause(final Throwable exception, Class<T> ecc) {
        Throwable ex = exception;
        while (ex != null) {
            if (ex.getCause() == null) {
                break;
            }
            ex = ex.getCause();
            if (ex.getClass().equals(ecc)) {
                return (T) ex;
            }
        }
        return null;
    }

    public static String getStackTrace(final Throwable throwable) {
        if (throwable == null) {
            return StringUtils.EMPTY;
        }
        final StringWriter sw = new StringWriter();
        throwable.printStackTrace(new PrintWriter(sw, true));
        return sw.toString();
    }

    public static String getSimpleStackTrace(Throwable throwable) {
        if (throwable == null) {
            return StringUtils.EMPTY;
        }
        // 获取完整堆栈
        String fullTrace = getFullStackTrace(throwable);
        // 长度不超过限制直接返回
        if (fullTrace.length() <= MAX_LENGTH) {
            return fullTrace;
        }
        // 智能截取关键部分
        return getEssentialStackTrace(fullTrace);
    }

    private static String getFullStackTrace(Throwable throwable) {
        StringWriter sw = new StringWriter();
        throwable.printStackTrace(new PrintWriter(sw, true));
        return sw.toString();
    }

    private static String getEssentialStackTrace(String fullTrace) {
        String[] lines = fullTrace.split("\n");
        List<String> essentialLines = new ArrayList<>();
        // 1. 保留开头重要信息
        addLines(essentialLines, lines, 0, Math.min(lines.length, HEAD_LINES));
        // 2. 提取关键错误位置
        extractImportantLines(essentialLines, lines);
        // 3. 保留异常链信息
        extractCauseChain(essentialLines, lines);
        // 4. 保留结尾重要信息
        if (lines.length > TAIL_LINES) {
            addTruncationMarker(essentialLines);
            addLines(essentialLines, lines, lines.length - TAIL_LINES, lines.length);
        }

        // 5. 组装结果并控制长度
        return joinWithLengthControl(essentialLines);
    }

    private static void extractImportantLines(List<String> essentialLines, String[] lines) {
        for (int i = HEAD_LINES; i < lines.length; i++) {
            if (isImportantLine(lines[i])) {
                // 添加上下文
                int start = Math.max(HEAD_LINES, i - KEY_CONTEXT_LINES);
                int end = Math.min(lines.length, i + KEY_CONTEXT_LINES + 1);
                // 避免重复添加已包含的行
                if (start > HEAD_LINES) {
                    addTruncationMarker(essentialLines);
                }

                addLines(essentialLines, lines, start, end);
                i = end; // 跳过已添加的区域
            }
        }
    }

    private static void extractCauseChain(List<String> essentialLines, String[] lines) {
        int causeCount = 0;
        for (int i = 0; i < lines.length; i++) {
            if (lines[i].contains("Caused by:") && causeCount < MAX_CAUSES) {
                // 添加异常链标记行
                if (causeCount > 0) {
                    addTruncationMarker(essentialLines);
                }

                // 提取关键上下文
                int start = Math.max(0, i - 1); // 包含上一行
                int end = Math.min(lines.length, i + KEY_CONTEXT_LINES + 1);

                addLines(essentialLines, lines, start, end);
                i = end; // 跳过已添加的区域
                causeCount++;
            }
        }
    }

    private static boolean isImportantLine(String line) {
        // 匹配关键错误模式
        return IMPORTANT_PATTERNS.matcher(line).find();
    }

    private static void addLines(List<String> essentialLines, String[] lines, int start, int end) {
        essentialLines.addAll(Arrays.asList(lines).subList(start, end));
    }

    private static void addTruncationMarker(List<String> essentialLines) {
        essentialLines.add("\n--- [truncated] ---\n");
    }

    private static String joinWithLengthControl(List<String> lines) {
        StringBuilder sb = new StringBuilder(MAX_LENGTH + 100);
        for (String line : lines) {
            int remaining = MAX_LENGTH - sb.length();
            if (remaining <= 0) break;

            if (line.length() > remaining) {
                sb.append(line, 0, remaining);
                break;
            }
            sb.append(line);
        }

        // 添加长度信息
        if (sb.length() >= MAX_LENGTH) {
            sb.append("\n\n[StackTrace truncated to ").append(sb.length()).append(" characters]");
        }

        return sb.toString();
    }
}
